﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CreateForeignKey.cs" company="SmartPlan">
//   SmartPlan 2011
// </copyright>
// <summary>
//   The create foreign key.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace DbDiff.Common.Scripting
{
    using System;
    using System.Data;
    using DataAccess;

    /// <summary>
    /// The create foreign key.
    /// </summary>
    internal class CreateForeignKey : CreateBase
    {
        /// <summary>
        /// The is only script.
        /// </summary>
        private readonly bool onlyScript;

        /// <summary>
        /// Gets sqlScript.
        /// </summary>
        public CreateTable sqlScript
        {
            get {return this.currentScript;}
        }

        /// <summary>
        /// The current script.
        /// </summary>
        private readonly CreateTable currentScript = new CreateTable() ;

        /// <summary>
        /// The IndexRow.
        /// </summary>
        protected DbObjectsDs.ForeignRow ir;

        /// <summary>
        /// Initializes a new instance of the <see cref="CreateForeignKey"/> class.
        /// </summary>
        /// <param name="schema">
        /// The schema.
        /// </param>
        /// <param name="tableName">
        /// The table name.
        /// </param>
        /// <param name="foreignKeyName">
        /// The foreign key name.
        /// </param>
        /// <param name="dtObjects">
        /// The dt objects.
        /// </param>
        /// <param name="scrOption">
        /// The scr option.
        /// </param>
        public CreateForeignKey(string schema, string tableName, string foreignKeyName, DatabaseDataSets dtObjects, SqlScriptingOption scrOption) : base(schema, tableName, foreignKeyName, dtObjects, scrOption)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CreateForeignKey"/> class.
        /// </summary>
        /// <param name="schema">
        /// The schema.
        /// </param>
        /// <param name="tableName">
        /// The table name.
        /// </param>
        /// <param name="foreignKeyName">
        /// The foreign key name.
        /// </param>
        /// <param name="dtObjects">
        /// The dt objects.
        /// </param>
        /// <param name="isOnlyScript">
        /// The is only script.
        /// </param>
        /// <param name="scrOption">
        /// The scr option.
        /// </param>
        /// <param name="sqlVersion">
        /// The sql version.
        /// </param>
        public CreateForeignKey(string schema, string tableName, string foreignKeyName, DatabaseDataSets dtObjects, bool isOnlyScript, SqlScriptingOption scrOption) : base(schema, tableName, foreignKeyName, dtObjects, scrOption)
        {
            this.onlyScript = true;
        }

        /// <summary>
        /// The set rows.
        /// </summary>
        protected override void SetRows()
        {
            this.DataRowViews = this.DatabaseDiffData.GetForeign(this.Schema, this.TableName, this.Name);
        }

        /// <summary>
        /// The set current row.
        /// </summary>
        protected override void SetCurrentRow()
        {
            if (this.DataRowViews.Length != 0)
            {
                this.ir = (DatabaseDataSets.ForeignRow)this.DataRowViews[this.CurrentRow].Row;
            }
        }

        /// <summary>
        /// The for key.
        /// </summary>
        private enum ForKey
        {
            /// <summary>
            /// The foreing key.
            /// </summary>
            Fkey = 0, 

            /// <summary>
            /// The reference key.
            /// </summary>
            Rkey = 1
        }

        /// <summary>
        /// The keys.
        /// </summary>
        /// <returns>
        /// </returns>
        private string[] Keys()
        {
            var keys = new string[2];

            DataRowView[] drv = this.DatabaseDiffData.GetForeignKeys(this.Schema, this.TableName, this.ir.Name);
            DbObjectsDs.ForeignKeyRow frk;

            if (drv.Length > 0)
            {
                foreach (DataRowView t in drv)
                {
                    frk = (DatabaseDataSets.ForeignKeyRow)t.Row;
                    keys[0] += QuoteName(frk.Fkey) + Comma;
                    keys[1] += QuoteName(frk.Rkey) + Comma;
                }
            }

            keys[0] = keys[0].Remove(keys[0].LastIndexOf(Comma), 1);
            keys[1] = keys[1].Remove(keys[1].LastIndexOf(Comma), 1);
            
            return keys;
        }

        /// <summary>
        /// The row script.
        /// </summary>
        protected override void RowScript()
        {
            if (this.ir != null)
            {
                var sqlString = new SqlString();
                bool alter = this.scrOption.Alter;

                if (this.scrOption.Drop)
                {
                    // drop
                    this.AddRow();
                    this.AddRow(string.Format("{0} {1} {2} {3} {4} {5}", 
                                              cmdAlter, 
                                              cmdTable, 
                                              QuoteName(this.Schema, this.TableName), 
                                              cmdDrop, 
                                              cmdConstraint, 
                                              this.Name));

                    this.currentScript.afterCreateForAlter.AddElement(sqlString.ToString(), false, false);
                    this.currentScript.afterCreateForAlter.AddCommandTerminator(string.Empty);
                }
                else
                {
                // alter or create
                    string[] keys = this.Keys();

                    // ha disabled, vagy nocheck, akkor csak alter lehet
                    // ha nincs neve, es nocheck, vagy disabled, akkor is csak alter, de a generalt nevet hozzarakja
                    if (this.ir.FkeyCnstIsDisabled | this.ir.FkeyCnstIsNotTrusted | alter | this.scrOption.Create)
                    {
                        // ALTER TABLE táblanév ADD
                        this.AddRow(string.Format("{0} {1} {2} {3} {4}", 
                                                  cmdAlter, 
                                                  cmdTable, 
                                                  QuoteName(this.Schema, this.TableName), 
                                                  cmdAdd, 
                                                  this.ir.FkeyCnstIsNotTrusted
                                                      ? cmdWithNoCheck
                                                      : string.Empty));
                        alter = true;
                    }

                    if ((!this.ir.NoName || this.onlyScript) || alter)
                    {
                        this.AddElement(string.Format("CONSTRAINT {0}", QuoteName(this.ir.Name)), true, true);
                    }

                    this.AddElement(string.Format("{0}", cmdForeign), true, true);
                    this.AddRow();
                    this.AddRowWithTabAndNewLine("(");
                    this.AddRowWithTabAndNewLine(keys[(int)ForKey.Fkey]);
                    this.AddRowWithTabAndNewLine(")");
                    this.AddRowWithTabAndNewLine(string.Format("{0} {1}", cmdReferences, QuoteName(this.ir.RSchema, this.ir.RTableName)));
                    this.AddRowWithTabAndNewLine("(");
                    this.AddRowWithTabAndNewLine(keys[(int)ForKey.Rkey]);
                    this.AddRowWithTabAndNewLine(")");

                    if (this.ir.FkeyDeleteCascade)
                    {
                        this.AddRowWithTabAndNewLine(string.Format("{0} {1}", cmdOnDelete, this.ir.FkeyDeleteCascade ? cmdCascade : cmdNoAction));
                    }

                    if (this.ir.FkeyUpdateCascade)
                    {
                        this.AddRowWithTabAndNewLine(string.Format("{0} {1}", cmdOnUpdate, this.ir.FkeyUpdateCascade ? cmdCascade : cmdNoAction));
                    }

                    if (this.ir.FkeyCnstIsNotForReplication)
                    {
                        this.AddRowWithTabAndNewLine(cmdNotForReplication);
                    }

                    this.RemoveToLastCrLf();

                    // ha nem alter, akkor kell csak a vessző
                    if (!alter)
                    {
                        this.AddRow(Comma);
                    }

                    if (alter)
                    {
                        this.currentScript.afterCreateForAlter.AddElement(sqlString.ToString(), false, false);
                        this.currentScript.afterCreateForAlter.AddCommandTerminator(string.Empty);

                        // 'alter table' +@candidate_table+case when @cDisabled=1 then N'NO' else N' ' end
                        // +N'CHECK CONSTRAINT '+@candidate_name+@cr
                        this.currentScript.afterCreateForAlter.AddRow(string.Format("{0} {1} {2} {3} {4}{5}"
                                                                                    , cmdAlter
                                                                                    , cmdTable
                                                                                    , 
                                                                                    QuoteName(
                                                                                        this.Schema, this.TableName)
                                                                                    , 
                                                                                    this.ir.FkeyCnstIsDisabled
                                                                                        ? cmdWithNoCheck
                                                                                        : cmdCheck
                                                                                    , 
                                                                                    string.Format("CONSTRAINT {0}", 
                                                                                                      
                                                                                                  QuoteName(
                                                                                                      this.ir.
                                                                                                          Name))
                                                                                    ,
                                                                                    CrLf +
                                                                                    CommandTerminator
                                                                          ));
                    }
                    else
                    {
                        this.currentScript.afterField.AddElement(sqlString.ToString(), false, false);
                    }
                }
            }


/*
                            set @sql=@sql+N' ALTER TABLE '+@candidate_table
                                    +case when @withnocheck=1 then ' WITH NOCHECK ' else '' end
                                    +@cr+@crt+N'ADD CONSTRAINT ' 
                                    +quotename(@candidate_name,N']')+N' FOREIGN KEY ('+
                                    +@candidate_key+N')'+@cr+@crt+'REFERENCES '+@reference_table+N' ('+@reference_key+')'+
                                    +@cr+@crt+case @cUpdateCascade when 1 then N'ON UPDATE CASCADE' else N'ON UPDATE NO ACTION' end
                                    +@cr+@crt+case @cDeleteCascade when 1 then N'ON DELETE CASCADE' else N'ON DELETE NO ACTION' end
                                    --we can disable/enable references
                                    +@cr+N'alter table' +@candidate_table+case when @cDisabled=1 then N'NO' else N' ' end
                                    +N'CHECK CONSTRAINT '+@candidate_name+@cr
                */
        }

        /// <summary>
        /// The make string.
        /// </summary>
        public void MakeString()
        {
            base.ToString();
        }

        /// <summary>
        /// The to string.
        /// </summary>
        /// <returns>
        /// The to string.
        /// </returns>
        /// <exception cref="Exception">
        /// </exception>
        public override string ToString()
        {
            throw new Exception("You can't use ToString()");
        }

        /// <summary>
        /// The script.
        /// </summary>
        /// <returns>
        /// The script.
        /// </returns>
        public override string Script()
        {            
            return base.ToString();
        }

        /// <summary>
        /// The drop.
        /// </summary>
        /// <returns>
        /// The drop.
        /// </returns>
        protected override string Drop()
        {

            /*AddRow(string.Format("{0} {1} {2} {3} {4}",
                                cmdAlter,
                                cmdTable,
                                SqlFormat(this.schema,this.tableName),
                                cmdAdd,
                */
            return string.Empty;
        }




    }
}